package edu.se.jai.websocketgateway.controller;


import edu.se.jai.openfeignapi.dto.*;
import edu.se.jai.openfeignapi.feign.GameServiceFeignApi;
import edu.se.jai.websocketgateway.dto.WebSocketMessage;
import edu.se.jai.websocketgateway.service.MessageSendService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.messaging.handler.annotation.DestinationVariable;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.messaging.simp.SimpMessageHeaderAccessor;
import org.springframework.stereotype.Controller;

import java.util.List;

/**
 * WebSocket控制器
 * 
 * 负责处理所有WebSocket消息，通过OpenFeign调用game-service，包括：
 * - 玩家连接和房间管理
 * - 房间生命周期控制（创建、加入、离开、解散）
 * - 游戏逻辑处理（开始、停止、猜测）
 * - 消息路由和广播
 * 
 * 消息路由规则：
 * - /app/* : 客户端发送消息到服务器（全局操作）
 * - /room/{roomId} : 客户端发送消息到服务器（房间内操作）
 * - /user/queue/response : 服务器发送点对点消息给客户端
 * - /room/{roomId} : 服务器发送房间广播消息
 * - /topic/roomUpdate : 服务器发送全局广播消息
 */
@Slf4j
@Controller
@RequiredArgsConstructor
public class WebSocketController {

    private final GameServiceFeignApi gameServiceClient;
    private final MessageSendService messageSendService;

    /**
     * 处理玩家连接请求
     */
    @MessageMapping("/connect")
    public void handleConnect(@Payload WebSocketMessage message, SimpMessageHeaderAccessor headerAccessor) {
        String sessionId = headerAccessor.getSessionId();
        
        // 从消息中提取玩家名称
        String playerName = (String)message.getData();

        log.info("玩家 {} 尝试连接，Session ID: {}", playerName, sessionId);

        // 通过Feign调用game-service注册玩家会话
        Result<String> result = gameServiceClient.registerPlayer(sessionId, playerName);
        
        if (result.isSuccess()) {
            // 连接成功，发送成功消息
            messageSendService.notifyConnect(playerName, sessionId, true, "连接成功");
        } else {
            // 连接失败，发送错误消息
            messageSendService.notifyConnect(playerName, sessionId, false, result.getErrorMessage());
        }
    }

    /**
     * 处理创建房间请求
     */
    @MessageMapping("/create")
    public void handleCreateRoom(SimpMessageHeaderAccessor headerAccessor) {
        String sessionId = headerAccessor.getSessionId();
        log.info("收到创建房间请求: sessionId={}", sessionId);

        // 通过Feign调用game-service创建房间
        Result<GameRoomDto> createResult = gameServiceClient.createRoom(sessionId);

        if (createResult.isSuccess()) {
            GameRoomDto room = createResult.getData();
            // 发送创建成功消息给创建者
            messageSendService.notifyCreate(room, sessionId);
            // 广播房间更新给所有玩家
            messageSendService.notifyRoomUpdate(room);
        } else {
            log.error("创建房间失败: {}", createResult.getErrorMessage());
            messageSendService.notifyErrorMessage(sessionId, createResult.getErrorMessage());
        }
    }

    /**
     * 处理加入房间请求
     */
    @MessageMapping("/join")
    public void handleJoinRoom(@Payload WebSocketMessage message, SimpMessageHeaderAccessor headerAccessor) {
        String sessionId = headerAccessor.getSessionId();
        
        // 从消息中提取房间ID
        String roomId = (String)message.getData();
        
        log.info("收到加入房间请求: roomId={}, sessionId={}", roomId, sessionId);

        // 通过Feign调用game-service加入房间
        Result<GameRoomDto> result = gameServiceClient.joinRoom(sessionId, roomId);

        if (result.isSuccess()) {
            GameRoomDto room = result.getData();
            // 发送加入成功消息给当前玩家
            messageSendService.notifyJoin(room, sessionId);
            // 广播房间更新给所有玩家
            messageSendService.notifyRoomUpdate(room);
        } else {
            log.error("加入房间失败: {}", result.getErrorMessage());
            messageSendService.notifyErrorMessage(sessionId, result.getErrorMessage());
        }
    }

    /**
     * 处理房间内消息（解散房间、离开房间、游戏操作等）
     */
    @MessageMapping("/room/{roomId}")
    public void handleRoomMessage(@Payload WebSocketMessage message,
                                 @DestinationVariable String roomId,
                                 SimpMessageHeaderAccessor headerAccessor) {
        String sessionId = headerAccessor.getSessionId();
        log.info("收到房间消息: type={}, roomId={}, sessionId={}", message.getType(), roomId, sessionId);
        
        switch (message.getType()) {
            case DISSOLVE:
                // 解散房间
                Result<GameRoomDto> dissolveResult = gameServiceClient.dissolveRoom(sessionId, roomId);
                if (dissolveResult.isSuccess()) {
                    GameRoomDto room = dissolveResult.getData();
                    messageSendService.notifyRoomDissolved(room);
                } else {
                    log.error("解散房间失败: {}", dissolveResult.getErrorMessage());
                    messageSendService.notifyErrorMessage(sessionId, dissolveResult.getErrorMessage());
                }
                break;
                
            case LEAVE:
                // 离开房间
                Result<GameRoomDto> leaveResult = gameServiceClient.leaveRoom(sessionId, roomId);
                if (leaveResult.isSuccess()) {
                    GameRoomDto room = leaveResult.getData();
                    // 先发送离开消息给房间内其他玩家
                    messageSendService.notifyLeave(room, sessionId);
                    // 再发送房间更新消息
                    messageSendService.notifyRoomUpdate(room);
                } else {
                    log.error("离开房间失败: {}", leaveResult.getErrorMessage());
                    messageSendService.notifyErrorMessage(sessionId, leaveResult.getErrorMessage());
                }
                break;

            case START_GAME:
                // 开始游戏
                Result<GameRoomDto> startResult = gameServiceClient.startGame(sessionId, roomId);
                if (startResult.isSuccess()) {
                    GameRoomDto room = startResult.getData();
                    messageSendService.notifyGameStart(room);
                } else {
                    log.error("开始游戏失败: {}", startResult.getErrorMessage());
                    messageSendService.notifyErrorMessage(sessionId, startResult.getErrorMessage());
                }
                break;

            case STOP_GAME:
                // 停止游戏
                Result<GameRoomDto> stopResult = gameServiceClient.stopGame(sessionId, roomId);
                if (stopResult.isSuccess()) {
                    GameRoomDto room = stopResult.getData();
                    messageSendService.notifyGameStop(room);
                } else {
                    log.error("停止游戏失败: {}", stopResult.getErrorMessage());
                    messageSendService.notifyErrorMessage(sessionId, stopResult.getErrorMessage());
                }
                break;

            case GUESS:
                // 猜测数字
                // 前端发送的data字段直接是猜测的数字（Integer类型）
                Object dataObj = message.getData();
                Integer guess = (Integer) dataObj;

                if (guess == null) {
                    messageSendService.notifyErrorMessage(sessionId, "猜测数字不能为空");
                    return;
                }

                // 通过Feign调用game-service进行猜测
                GuessDto request = new GuessDto(sessionId, roomId, guess);
                Result<GuessResultDto> guessResult = gameServiceClient.makeGuess(request);

                if (guessResult.isSuccess()) {
                    GuessResultDto resultData = guessResult.getData();
                    String playerName = resultData.getPlayerName();
                    Boolean result = resultData.getResult();
                    String hint = resultData.getHint();

                    // 发送猜测结果
                    messageSendService.notifyGuessResult(roomId, playerName, guess, result, hint, sessionId);

                } else {
                    log.error("猜测失败: {}", guessResult.getErrorMessage());
                    messageSendService.notifyErrorMessage(sessionId, guessResult.getErrorMessage());
                }
                break;
                
            default:
                log.warn("未知的房间消息类型: {}", message.getType());
                messageSendService.notifyErrorMessage(sessionId, "未知的消息类型: " + message.getType());
        }
    }

    /**
     * 处理获取所有房间列表请求
     */
    @MessageMapping("/allRooms")
    public void handleGetAllRooms(SimpMessageHeaderAccessor headerAccessor) {
        String sessionId = headerAccessor.getSessionId();
        log.info("获取所有房间列表请求，会话ID: {}", sessionId);
        
        // 通过Feign调用game-service获取所有房间
        Result<List<GameRoomDto>> allRoomsResult = gameServiceClient.getAllRooms();
        if (allRoomsResult.isFailure() || allRoomsResult.getData() == null) {
            log.warn("获取房间列表失败");
            messageSendService.notifyErrorMessage(sessionId, "获取房间列表失败");
            return;
        }
        
        List<GameRoomDto> allRooms = allRoomsResult.getData();
        log.info("找到 {} 个房间", allRooms.size());

        // 发送房间列表给请求者
        messageSendService.notifyAllRooms(allRooms, sessionId);
    }
}

